package cn.lingyangwl.agile.system.service.impl;

import cn.lingyangwl.agile.auth.AuthApi;
import cn.lingyangwl.agile.system.assembly.SysMenuAssembly;
import cn.lingyangwl.agile.system.model.entity.SysMenu;
import cn.lingyangwl.agile.system.model.entity.SysRoleMenu;
import cn.lingyangwl.agile.system.manager.SysMenuManager;
import cn.lingyangwl.agile.system.manager.SysRoleMenuRelManager;
import cn.lingyangwl.agile.system.model.rqrs.role.RolePermResp;
import cn.lingyangwl.agile.system.model.rqrs.role.AssignRolePermissionReq;
import cn.lingyangwl.agile.system.service.SysMenuService;
import cn.lingyangwl.agile.system.service.SysRolePermissionService;
import cn.lingyangwl.framework.tool.core.CollectionUtils;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Service
public class SysRolePermissionServiceImpl implements SysRolePermissionService {
    private static final Logger log = LoggerFactory.getLogger(SysRolePermissionServiceImpl.class);
    @Resource
    private SysRoleMenuRelManager roleMenuRelManager;
    @Resource
    private SysMenuManager sysMenuManager;
    @Resource
    private SysMenuAssembly sysMenuAssembly;
    @Resource
    private SysMenuService menuService;
    @Resource
    private AuthApi authApi;
    @Override
    public List<RolePermResp> listRolePermission(Long roleId) {
        LambdaQueryWrapper<SysRoleMenu> queryWrapper = new QueryWrapper<SysRoleMenu>().lambda()
                .eq(SysRoleMenu::getRoleId, roleId);
        List<SysRoleMenu> menuRelPOList = roleMenuRelManager.list(queryWrapper);
        List<Long> menuIds = menuRelPOList.stream().map(SysRoleMenu::getMenuId)
                .collect(Collectors.toList());
        return sysMenuManager.listMenuDataByIds(menuIds).stream().map(sysMenuAssembly::toRolePermResp)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRolePermission(AssignRolePermissionReq req) {
        List<Long> newMenuIds = StringUtils.toList(req.getPermissionIds(), ",", Long.class);
        Set<Long> newPermissionIdList = menuService.reserveTreeBtnAndLeaf(newMenuIds);
        Long roleId = req.getRoleId();
        // 旧权限ids
        Set<Long> oldPermissionIds = listRolePermission(roleId).stream().map(RolePermResp::getMenuId)
                .collect(Collectors.toSet());
        // 计算添加的数据
        Set<Long> addMenuIds = new HashSet<>(newPermissionIdList);
        addMenuIds.removeAll(oldPermissionIds);

        // 计算被删除的元素
        Set<Long> deleteMenuIds = new HashSet<>(oldPermissionIds);
        deleteMenuIds.removeAll(newPermissionIdList);

        List<SysRoleMenu> roleMenuRelSavedList = null;
        Map<Long, SysMenu> menuDataMap = this.sysMenuManager.listMenuDataByIds(new ArrayList<>(addMenuIds)).stream()
                .collect(Collectors.toMap(SysMenu::getId, Function.identity()));

        if (CollectionUtils.isNotEmpty(addMenuIds)) {
            roleMenuRelSavedList = addMenuIds.stream().filter(Objects::nonNull).map(e -> {
                SysRoleMenu data = new SysRoleMenu();
                data.setRoleId(req.getRoleId());
                data.setMenuId(e);
                data.setResourceAction(Optional.ofNullable(menuDataMap.get(e)).map(SysMenu::getPerms).orElse(null));
                data.setSceneId(Optional.ofNullable(menuDataMap.get(e)).map(SysMenu::getSceneId).orElse(null));
                return data;
            }).collect(Collectors.toList());
        }

        if (CollectionUtils.isNotEmpty(roleMenuRelSavedList)) {
            if (!roleMenuRelManager.saveBatch(roleMenuRelSavedList)) {
                throw new BizException("批量保存权限失败");
            }
            log.debug("batch save roleMenuRel, size: {}", roleMenuRelSavedList.size());
        }

        if (CollectionUtils.isNotEmpty(deleteMenuIds)) {
            LambdaQueryWrapper<SysRoleMenu> queryWrapper = new QueryWrapper<SysRoleMenu>().lambda()
                    .eq(SysRoleMenu::getRoleId, roleId).in(SysRoleMenu::getMenuId, deleteMenuIds);
            roleMenuRelManager.remove(queryWrapper);
        }

        // 刷新绑定该角色的客户端
        authApi.refreshClientAuthorityByRoleIds(Collections.singletonList(roleId), false);
    }
}

